#include "stdafx.h"
#include "charset/unicodeconverter.hpp"
#include "charset/textencode.hpp"
#include "charset/textiterator.hpp"
#include "charset/textconverter.hpp"
#include "stdlib/bugcheck.hpp"
using namespace JHCPP::stdlib;

namespace JHCPP
{
	namespace charset
	{	
		void CUnicodeConverter::toUTF16(const std::string& utf8String, std::wstring& utf16String)
		{
			utf16String.clear();
			CUTF8Encode utf8Encode;
			CTextIterator it(utf8String, utf8Encode);
			CTextIterator end(utf8String);
			while (it != end) 
			{
				int cc = *it++;
				if (cc <= 0xffff)
				{
					utf16String += (wchar_t) cc;
				}
				else
				{
					cc -= 0x10000;
					utf16String += (wchar_t) ((cc >> 10) & 0x3ff) | 0xd800;
					utf16String += (wchar_t) (cc & 0x3ff) | 0xdc00;
				}
			}
		}

		void CUnicodeConverter::toUTF16(const char* utf8String, int length, std::wstring& utf16String)
		{
			jh_check_ptr (utf8String);

			utf16String.clear();

			CUTF8Encode utf8Encode;
			const unsigned char* it  = (const unsigned char*) utf8String;
			const unsigned char* end = (const unsigned char*) utf8String + length;

			while (it < end)
			{
				int n = utf8Encode.queryConvert(it, 1);
				int uc;
				int read = 1;

				while (-1 > n && (end - it) >= -n)
				{
					read = -n;
					n = utf8Encode.queryConvert(it, read);
				}

				if (-1 > n)
				{
					it = end;
				}
				else
				{
					it += read;
				}

				if (-1 >= n)
				{
					uc = 0xfffd;	// Replacement Character (instead of '?')
				}
				else
				{
					uc = n;
				}

				if (uc > 0xffff)
				{
					uc -= 0x10000;
					utf16String += (wchar_t) ((uc >> 10) & 0x3ff) | 0xd800 ;
					utf16String += (wchar_t) (uc & 0x3ff) | 0xdc00 ;
				}
				else
				{
					utf16String += (wchar_t) uc;
				}
			}
		}

		void CUnicodeConverter::toUTF16(const char* utf8String, std::wstring& utf16String)
		{
			toUTF16(utf8String, (int) std::strlen(utf8String), utf16String);
		}

		void CUnicodeConverter::toUTF8(const std::wstring& utf16String, std::string& utf8String)
		{
			utf8String.clear();
			CUTF8Encode utf8Encode;
			CUTF16Encode utf16Encode;
			CTextConverter converter(utf16Encode, utf8Encode);
			converter.convert(utf16String.data(), (int) utf16String.length()*sizeof(wchar_t), utf8String);
		}

		void CUnicodeConverter::toUTF8(const wchar_t* utf16String, int length, std::string& utf8String)
		{
			utf8String.clear();
			CUTF8Encode utf8Encode;
			CUTF16Encode utf16Encode;
			CTextConverter converter(utf16Encode, utf8Encode);
			converter.convert(utf16String, (int) length*sizeof(wchar_t), utf8String);
		}

		void CUnicodeConverter::toUTF8(const wchar_t* utf16String, std::string& utf8String)
		{
			toUTF8(utf16String, (int) wcslen(utf16String), utf8String);
		}

	}//end of namespace charset
}//end of namespace JHCPP
